<?php

// 公共助手函数

use fast\Http;
use think\Db;
use think\Exception;
use think\exception\HttpResponseException;
use think\exception\PDOException;
use think\Response;

if (!function_exists('__')) {

    /**
     * 获取语言变量值
     * @param string $name 语言变量名
     * @param string | array  $vars 动态变量值
     * @param string $lang 语言
     * @return mixed
     */
    function __($name, $vars = [], $lang = '')
    {
        if (is_numeric($name) || !$name) {
            return $name;
        }
        if (!is_array($vars)) {
            $vars = func_get_args();
            array_shift($vars);
            $lang = '';
        }
        return \think\Lang::get($name, $vars, $lang);
    }
}

if (!function_exists('format_bytes')) {

    /**
     * 将字节转换为可读文本
     * @param int    $size      大小
     * @param string $delimiter 分隔符
     * @param int    $precision 小数位数
     * @return string
     */
    function format_bytes($size, $delimiter = '', $precision = 2)
    {
        $units = array('B', 'KB', 'MB', 'GB', 'TB', 'PB');
        for ($i = 0; $size >= 1024 && $i < 5; $i++) {
            $size /= 1024;
        }
        return round($size, $precision) . $delimiter . $units[$i];
    }
}

if (!function_exists('datetime')) {

    /**
     * 将时间戳转换为日期时间
     * @param int    $time   时间戳
     * @param string $format 日期时间格式
     * @return string
     */
    function datetime($time, $format = 'Y-m-d H:i:s')
    {
        $time = is_numeric($time) ? $time : strtotime($time);
        return date($format, $time);
    }
}

if (!function_exists('human_date')) {

    /**
     * 获取语义化时间
     * @param int $time  时间
     * @param int $local 本地时间
     * @return string
     */
    function human_date($time, $local = null)
    {
        return \fast\Date::human($time, $local);
    }
}

if (!function_exists('cdnurl')) {

    /**
     * 获取上传资源的CDN的地址
     * @param string  $url    资源相对地址
     * @param boolean $domain 是否显示域名 或者直接传入域名
     * @return string
     */
    function cdnurl($url, $domain = false)
    {
        $regex = "/^((?:[a-z]+:)?\/\/|data:image\/)(.*)/i";
        $cdnurl = \think\Config::get('upload.cdnurl');
        if (is_bool($domain) || stripos($cdnurl, '/') === 0) {
            $url = preg_match($regex, $url) || ($cdnurl && stripos($url, $cdnurl) === 0) ? $url : $cdnurl . $url;
        }
        if ($domain && !preg_match($regex, $url)) {
            $domain = is_bool($domain) ? request()->domain() : $domain;
            $url = $domain . $url;
        }
        return $url;
    }
}


if (!function_exists('is_really_writable')) {

    /**
     * 判断文件或文件夹是否可写
     * @param string $file 文件或目录
     * @return    bool
     */
    function is_really_writable($file)
    {
        if (DIRECTORY_SEPARATOR === '/') {
            return is_writable($file);
        }
        if (is_dir($file)) {
            $file = rtrim($file, '/') . '/' . md5(mt_rand());
            if (($fp = @fopen($file, 'ab')) === false) {
                return false;
            }
            fclose($fp);
            @chmod($file, 0777);
            @unlink($file);
            return true;
        } elseif (!is_file($file) or ($fp = @fopen($file, 'ab')) === false) {
            return false;
        }
        fclose($fp);
        return true;
    }
}

if (!function_exists('rmdirs')) {

    /**
     * 删除文件夹
     * @param string $dirname  目录
     * @param bool   $withself 是否删除自身
     * @return boolean
     */
    function rmdirs($dirname, $withself = true)
    {
        if (!is_dir($dirname)) {
            return false;
        }
        $files = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($dirname, RecursiveDirectoryIterator::SKIP_DOTS),
            RecursiveIteratorIterator::CHILD_FIRST
        );

        foreach ($files as $fileinfo) {
            $todo = ($fileinfo->isDir() ? 'rmdir' : 'unlink');
            $todo($fileinfo->getRealPath());
        }
        if ($withself) {
            @rmdir($dirname);
        }
        return true;
    }
}

if (!function_exists('copydirs')) {

    /**
     * 复制文件夹
     * @param string $source 源文件夹
     * @param string $dest   目标文件夹
     */
    function copydirs($source, $dest)
    {
        if (!is_dir($dest)) {
            mkdir($dest, 0755, true);
        }
        foreach (
            $iterator = new RecursiveIteratorIterator(
                new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS),
                RecursiveIteratorIterator::SELF_FIRST
            ) as $item
        ) {
            if ($item->isDir()) {
                $sontDir = $dest . DS . $iterator->getSubPathName();
                if (!is_dir($sontDir)) {
                    mkdir($sontDir, 0755, true);
                }
            } else {
                copy($item, $dest . DS . $iterator->getSubPathName());
            }
        }
    }
}

if (!function_exists('mb_ucfirst')) {
    function mb_ucfirst($string)
    {
        return mb_strtoupper(mb_substr($string, 0, 1)) . mb_strtolower(mb_substr($string, 1));
    }
}

if (!function_exists('addtion')) {

    /**
     * 附加关联字段数据
     * @param array $items  数据列表
     * @param mixed $fields 渲染的来源字段
     * @return array
     */
    function addtion($items, $fields)
    {
        if (!$items || !$fields) {
            return $items;
        }
        $fieldsArr = [];
        if (!is_array($fields)) {
            $arr = explode(',', $fields);
            foreach ($arr as $k => $v) {
                $fieldsArr[$v] = ['field' => $v];
            }
        } else {
            foreach ($fields as $k => $v) {
                if (is_array($v)) {
                    $v['field'] = $v['field'] ?? $k;
                } else {
                    $v = ['field' => $v];
                }
                $fieldsArr[$v['field']] = $v;
            }
        }
        foreach ($fieldsArr as $k => &$v) {
            $v = is_array($v) ? $v : ['field' => $v];
            $v['display'] = $v['display'] ?? str_replace(['_ids', '_id'], ['_names', '_name'], $v['field']);
            $v['primary'] = $v['primary'] ?? '';
            $v['column'] = $v['column'] ?? 'name';
            $v['model'] = $v['model'] ?? '';
            $v['table'] = $v['table'] ?? '';
            $v['name'] = $v['name'] ?? str_replace(['_ids', '_id'], '', $v['field']);
        }
        unset($v);
        $ids = [];
        $fields = array_keys($fieldsArr);
        foreach ($items as $k => $v) {
            foreach ($fields as $m => $n) {
                if (isset($v[$n])) {
                    $ids[$n] = array_merge(isset($ids[$n]) && is_array($ids[$n]) ? $ids[$n] : [], explode(',', $v[$n]));
                }
            }
        }
        $result = [];
        foreach ($fieldsArr as $k => $v) {
            if ($v['model']) {
                $model = new $v['model'];
            } else {
                // 优先判断使用table的配置
                $model = $v['table'] ? \think\Db::table($v['table']) : \think\Db::name($v['name']);
            }
            $primary = $v['primary'] ?: $model->getPk();
            $result[$v['field']] = isset($ids[$v['field']]) ? $model->where($primary, 'in', $ids[$v['field']])->column($v['column'], $primary) : [];
        }

        foreach ($items as $k => &$v) {
            foreach ($fields as $m => $n) {
                if (isset($v[$n])) {
                    $curr = array_flip(explode(',', $v[$n]));

                    $linedata = array_intersect_key($result[$n], $curr);
                    $v[$fieldsArr[$n]['display']] = $fieldsArr[$n]['column'] == '*' ? $linedata : implode(',', $linedata);
                }
            }
        }
        return $items;
    }
}

if (!function_exists('var_export_short')) {

    /**
     * 使用短标签打印或返回数组结构
     * @param mixed   $data
     * @param boolean $return 是否返回数据
     * @return string
     */
    function var_export_short($data, $return = true)
    {
        return var_export($data, $return);
    }
}

if (!function_exists('letter_avatar')) {
    /**
     * 首字母头像
     * @param $text
     * @return string
     */
    function letter_avatar($text)
    {
        $total = unpack('L', hash('adler32', $text, true))[1];
        $hue = $total % 360;
        list($r, $g, $b) = hsv2rgb($hue / 360, 0.3, 0.9);

        $bg = "rgb({$r},{$g},{$b})";
        $color = "#ffffff";
        $first = mb_strtoupper(mb_substr($text, 0, 1));
        $src = base64_encode('<svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="100" width="100"><rect fill="' . $bg . '" x="0" y="0" width="100" height="100"></rect><text x="50" y="50" font-size="50" text-copy="fast" fill="' . $color . '" text-anchor="middle" text-rights="admin" dominant-baseline="central">' . $first . '</text></svg>');
        $value = 'data:image/svg+xml;base64,' . $src;
        return $value;
    }
}

if (!function_exists('hsv2rgb')) {
    function hsv2rgb($h, $s, $v)
    {
        $r = $g = $b = 0;

        $i = floor($h * 6);
        $f = $h * 6 - $i;
        $p = $v * (1 - $s);
        $q = $v * (1 - $f * $s);
        $t = $v * (1 - (1 - $f) * $s);

        switch ($i % 6) {
            case 0:
                $r = $v;
                $g = $t;
                $b = $p;
                break;
            case 1:
                $r = $q;
                $g = $v;
                $b = $p;
                break;
            case 2:
                $r = $p;
                $g = $v;
                $b = $t;
                break;
            case 3:
                $r = $p;
                $g = $q;
                $b = $v;
                break;
            case 4:
                $r = $t;
                $g = $p;
                $b = $v;
                break;
            case 5:
                $r = $v;
                $g = $p;
                $b = $q;
                break;
        }

        return [
            floor($r * 255),
            floor($g * 255),
            floor($b * 255)
        ];
    }
}

if (!function_exists('check_nav_active')) {
    /**
     * 检测会员中心导航是否高亮
     */
    function check_nav_active($url, $classname = 'active')
    {
        $auth = \app\common\library\Auth::instance();
        $requestUrl = $auth->getRequestUri();
        $url = ltrim($url, '/');
        return $requestUrl === str_replace(".", "/", $url) ? $classname : '';
    }
}

if (!function_exists('check_cors_request')) {
    /**
     * 跨域检测
     */
    function check_cors_request()
    {
        if (isset($_SERVER['HTTP_ORIGIN']) && $_SERVER['HTTP_ORIGIN'] && config('fastadmin.cors_request_domain')) {
            $info = parse_url($_SERVER['HTTP_ORIGIN']);
            $domainArr = explode(',', config('fastadmin.cors_request_domain'));
            $domainArr[] = request()->host(true);
            if (in_array("*", $domainArr) || in_array($_SERVER['HTTP_ORIGIN'], $domainArr) || (isset($info['host']) && in_array($info['host'], $domainArr))) {
                header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']);
            } else {
                $response = Response::create('跨域检测无效', 'html', 403);
                throw new HttpResponseException($response);
            }

            header('Access-Control-Allow-Credentials: true');
            header('Access-Control-Max-Age: 86400');

            if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
                if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'])) {
                    header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
                }
                if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'])) {
                    header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
                }
                $response = Response::create('', 'html');
                throw new HttpResponseException($response);
            }
        }
    }
}

if (!function_exists('xss_clean')) {
    /**
     * 清理XSS
     */
    function xss_clean($content, $is_image = false)
    {
        return \app\common\library\Security::instance()->xss_clean($content, $is_image);
    }
}

if (!function_exists('url_clean')) {
    /**
     * 清理URL
     */
    function url_clean($url)
    {
        if (!check_url_allowed($url)) {
            return '';
        }
        return xss_clean($url);
    }
}

if (!function_exists('check_ip_allowed')) {
    /**
     * 检测IP是否允许
     * @param string $ip IP地址
     */
    function check_ip_allowed($ip = null)
    {
        $ip = is_null($ip) ? request()->ip() : $ip;
        $forbiddenipArr = config('site.forbiddenip');
        $forbiddenipArr = !$forbiddenipArr ? [] : $forbiddenipArr;
        $forbiddenipArr = is_array($forbiddenipArr) ? $forbiddenipArr : array_filter(explode("\n", str_replace("\r\n", "\n", $forbiddenipArr)));
        if ($forbiddenipArr && \Symfony\Component\HttpFoundation\IpUtils::checkIp($ip, $forbiddenipArr)) {
            $response = Response::create('请求无权访问', 'html', 403);
            throw new HttpResponseException($response);
        }
    }
}

if (!function_exists('check_url_allowed')) {
    /**
     * 检测URL是否允许
     * @param string $url URL
     * @return bool
     */
    function check_url_allowed($url = '')
    {
        //允许的主机列表
        $allowedHostArr = [
            strtolower(request()->host())
        ];

        if (empty($url)) {
            return true;
        }

        //如果是站内相对链接则允许
        if (preg_match("/^[\/a-z][a-z0-9][a-z0-9\.\/]+((\?|#).*)?\$/i", $url) && substr($url, 0, 2) !== '//') {
            return true;
        }

        //如果是站外链接则需要判断HOST是否允许
        if (preg_match("/((http[s]?:\/\/)+((?>[a-z\-0-9]{2,}\.)+[a-z]{2,8}|((?>([0-9]{1,3}\.)){3}[0-9]{1,3}))(:[0-9]{1,5})?)(?:\s|\/)/i", $url)) {
            $chkHost = parse_url(strtolower($url), PHP_URL_HOST);
            if ($chkHost && in_array($chkHost, $allowedHostArr)) {
                return true;
            }
        }

        return false;
    }
}

if (!function_exists('build_suffix_image')) {
    /**
     * 生成文件后缀图片
     * @param string $suffix 后缀
     * @param null   $background
     * @return string
     */
    function build_suffix_image($suffix, $background = null)
    {
        $suffix = mb_substr(strtoupper($suffix), 0, 4);
        $total = unpack('L', hash('adler32', $suffix, true))[1];
        $hue = $total % 360;
        list($r, $g, $b) = hsv2rgb($hue / 360, 0.3, 0.9);

        $background = $background ? $background : "rgb({$r},{$g},{$b})";

        $icon = <<<EOT
        <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
            <path style="fill:#E2E5E7;" d="M128,0c-17.6,0-32,14.4-32,32v448c0,17.6,14.4,32,32,32h320c17.6,0,32-14.4,32-32V128L352,0H128z"/>
            <path style="fill:#B0B7BD;" d="M384,128h96L352,0v96C352,113.6,366.4,128,384,128z"/>
            <polygon style="fill:#CAD1D8;" points="480,224 384,128 480,128 "/>
            <path style="fill:{$background};" d="M416,416c0,8.8-7.2,16-16,16H48c-8.8,0-16-7.2-16-16V256c0-8.8,7.2-16,16-16h352c8.8,0,16,7.2,16,16 V416z"/>
            <path style="fill:#CAD1D8;" d="M400,432H96v16h304c8.8,0,16-7.2,16-16v-16C416,424.8,408.8,432,400,432z"/>
            <g><text><tspan x="220" y="380" font-size="124" font-family="Verdana, Helvetica, Arial, sans-serif" fill="white" text-anchor="middle">{$suffix}</tspan></text></g>
        </svg>
EOT;
        return $icon;
    }
}





/**
 * 全境供应链云-获取省市区地址
 * @param int $level 级别
 * @return array
 */
function loadRegionFromApi(int $level=1):array{
    $sceApiService=new \fast\SceApiService();
    function save_area_datas($data,$areaData,$pid){
        foreach ($areaData as $item) {
            $data[] = [
                'id' => $item['id'],
                'pid' =>$pid,
                'name' => $item['name'],
                'shortname' => $item['name'],
                'mergename' => $item['regionFullName'],
                'level' => $item['regionLevel'],
                'code' => $item['regionCode'],
                'parentcode' => $item['parentCode'],
                'first' => $item['initial'],
                'lng' => $item['longitude'],
                'lat' => $item['latitude']
            ];
        }
        return $data;
    }

    $areas=model('app\common\model\Area')->where('level',$level)->where('zip is null')->limit(2)->select();
    $data=[];$msg='';
    Db::startTrans();
   try {
       if ($areas) {
           foreach ($areas as $area) {
               $sub_areas = $sceApiService->getRegionByCodeOpen($area['code']);
               if (is_array($sub_areas) && isset($sub_areas['code'])) {
                   throw new \think\Exception($sub_areas['msg']);
               }
               if ($sub_areas) {
                   $data = save_area_datas($data, $sub_areas, $area['id']);
               }
               //把查询过的更新为zip=1标识
               $area->zip = 1;
               $area->allowField(['zip'])->save();
               $msg .= "更新了 {$area['code']} <br/>";
           }
       } else {
           if (!model('app\common\model\Area')->where('level', $level)->count()) {
               $areas = $sceApiService->getRegionByCodeOpen();
               if (is_array($areas) && isset($areas['code'])) {
                   throw new \think\Exception($areas['msg']);
               }
               if ($areas) {
                   $data = save_area_datas($data, $areas, 0);
               }
               $msg = "{$level}级导入成功";
           } else {
               $level += 1;
               $msg = "{$level}级导入成功";
           }
       }
       if ($data) {
           model('app\common\model\Area')->saveAll($data, false);
       }

       Db::commit();
       echo $msg;
       return ['code'=>1,'msg'=>'操作成功'];
   }catch (\Exception $e){
       Db::rollback();
       return ['code'=>0,'msg'=>$e->getMessage()];
   }
}


/**
 * 全境供应链云-从消息池中获取消息
 * @return void
 */
function getMessage(){
    $sceApiService=new \fast\SceApiService();
    $msgList=$sceApiService->getMessage();
    print_r($msgList);exit;
}


/**
 * 全境供应链云-获取分类
 * @param int $pid 上级类目ID,一级类目的上级为0
 * @param bool $isReturn 是否需要返回数据,默认为false
 * @return array
 */
function loadCategorysFromApi(int $pid,bool $isReturn=false):array{
    if(model('app\common\model\wanlshop\Category')->where('pid',$pid)->count()) return [];
    $sceApiService=new \fast\SceApiService();
    $categories=$sceApiService->getCategorys($pid);
    if(is_array($categories) && isset($categories['code'])) return $categories;

    $data=[];
    foreach($categories as $item){
        $data[]=[
            'id'=>$item['id'],
            'pid'=>$item['pid'],
            'type'=>'goods',
            'name'=>$item['name'],
            'status'=>'normal'
        ];
    }
    if($isReturn) return $data;
    model('app\common\model\wanlshop\Category')->saveAll($data,false);
    return [];
}



/**
 * 全境供应链云-获取品牌
 * @return array
 */
function loadBrandsFromApi():array{
    //admin_id=0:全境品牌,admin_id>0:自建品牌
    if(model('app\common\model\wanlshop\Brand')->where('admin_id',0)->count()) return [];
    $sceApiService=new \fast\SceApiService();
    $brands=$sceApiService->getBrands(1,1);
    if(is_array($brands) && isset($brands['code'])) return $brands;
    $brands=$sceApiService->getBrands(1,$brands['total']);
    if(is_array($brands) && isset($brands['code'])) return $brands;
    $data=[];
    foreach($brands['records'] as $item){
        $data[]=[
            'id'=>$item['id'],
            'name'=>$item['name'],
            'image'=>$item['logoPath']
        ];
    }
    model('app\common\model\wanlshop\Brand')->saveAll($data,false);
    return [];
}


/**
 * 全境供应链云-查询SPU商品详情
 * @param array $spuIdList spuId二维数组,因为一次最多200个,如[['1478925483308531713','1491659531545055233']]
 * @return array 商品详情数组
 */
function getSpuBySpuIds(array $spuIdList):array{
    $sceApiService=new \fast\SceApiService();
    $spuListAll=[];
    foreach($spuIdList as $list){
        $spuList= $sceApiService->getSpuBySpuIds($list);
        if(is_array($spuList) && isset($spuList['code'])) return $spuList;
        if(!$spuList) continue;
        $spuListAll=array_merge($spuListAll,$spuList);
    }
    return $spuListAll;
}




/**
 * 全境供应链云-查询商品库SPUID列表
 * @param int $shop_id 店铺ID
 * @return array
 */
function loadGoodsListFromApi(int $shop_id):array{
    if(model('app\common\model\wanlshop\Goods')->where('shop_id',$shop_id)->where('spuId','<>','0')->count()) return [];

    $sceApiService=new \fast\SceApiService();
    $spuIdListData=$sceApiService->getSpuIdList();
    if(is_array($spuIdListData) && isset($spuIdListData['code'])) return $spuIdListData;

    $goodsData = [];$spuIdList[]=$spuIdListData['spuIdList'];
    for($i=2;$i<=$spuIdListData['pages'];$i++) {
        $spuIdListData = $sceApiService->getSpuIdList($i);
        if(is_array($spuIdListData) && isset($spuIdListData['code'])) return $spuIdListData;
        if (!$spuIdListData['spuIdList']) continue;
        $spuIdList[]=$spuIdListData['spuIdList'];
    }

    $spuListAll=getSpuBySpuIds($spuIdList);
    if(isset($spuListAll['code'])) return $spuListAll;

    foreach ($spuListAll as $item) {
        //status	全境商品状态：0、已上架1、已下架
        $goodsData[] =$item['status']?[]:[
            'spuId' => $item['spuId'],
            'shop_id' => $shop_id,
            'shop_category_id' => 1,
            'category_id' => $item['categoryId3'] ?? ($item['categoryId2'] ?? $item['categoryId1']),
            'brand_id' => $item['brandId'],
            'title' => $item['name'],
            'image' => $item['carouselImgList'] ? $item['carouselImgList'][0] : ($item['detailImgList'] ? $item['detailImgList'][0] : ''),
            'images' =>$item['carouselImgList'] ? implode(',', $item['carouselImgList']) :($item['detailImgList'] ? implode(',', $item['detailImgList']):''),
            'description' => '',
            'content' =>$item['detailImgList'] ? implode(',', $item['detailImgList']) :'',
            'freight_id' => 1,
            'freeExpress' => $item['freeExpress']
        ];
    }
    return $goodsData?model('app\common\model\wanlshop\Goods')->saveAll($goodsData,false):[];
}



/**
 * 全境供应链云-查询SKU规格信息
 * @param \app\common\model\wanlshop\Goods $goods 商品实例
 * @return void
 */
function loadSkuInfoFromApi(\app\common\model\wanlshop\Goods $goods,array $skuData=[],array $spuData=[]):array{
    $spuId=$goods['spuId'];
    $sceApiService=new \fast\SceApiService();
    $skuInfo=$sceApiService->listSkuBySpuId($spuId);
    if(is_array($skuInfo) && isset($skuInfo['code'])) return $skuInfo;

    $spu_item=$specName=$price='';
    foreach($skuInfo as $item){
        //status	商品状态：0、已上架1、已下架
        if($item['status']==0) {
            foreach($item['skuPropertyList'] as $sku) {
                $specName=$specName==''?$sku['specName']:$specName;
                $spu_item=$spu_item==''?$sku['specValueName']:$spu_item.','.$sku['specValueName'];
                //$price=$price==''?$item['suggestPrice']:$price;//建议零售价
                $price=$price==''?$item['officialDistriPrice']:$price;//市场价
                $skuData[]= [
                    'goods_id'=>$goods['id'],
                    'skuId' => $item['skuId'],
                    'spuId'=>$spuId,
                    'thumbnail' => $item['skuPicUrl'],
                    'difference' =>$sku['specValueName'],
                    //'price' =>$item['suggestPrice'],//建议零售价
                    'price' => $item['officialDistriPrice'],//市场价
                    'market_price' =>$item['officialDistriPrice'],//市场价
                    'stock' => $item['stock'],
                    'status' => $item['status'] ? 'hidden' : 'normal',
                ];
            }
        }
    }
    if($specName && $spu_item){
        $spuData[]=[
            'goods_id'=>$goods['id'],
            'spuId' => $spuId,
            'name' =>$specName,
            'item' => $spu_item,
            'status' =>'normal'
        ];
    }
    $goods['price']=$price;
    return compact('goods','skuData','spuData');
}



/**
 * 批量校验下单商品销售范围和库存
 * @param array $itemDTOList sku库存数组,包含skuId(skuId,integer,是否必填:true)和skuNum(sku数量,integer,是否必填:true)
 * @param string $areaRegionCode 地区编码，四级区域编码，实在没有传三级区域编码    string    是否必填:true
 * @return string
 */
function checkSkuStock(array $itemDTOList,string $areaRegionCode):string{
    $sceApiService=new \fast\SceApiService();
    $resp=$sceApiService->checkSkuStock($itemDTOList,$areaRegionCode);
    if(is_array($resp) && isset($resp['code'])) return $resp['msg'];
    $resp=$resp[0];
    $sailState= (bool)$resp['sailState'];//是否可销售,1,可销售，0不可销售
    $stockState= (bool)$resp['stockState'];//是否有货,1有货，0无货
    $msg=$resp['msg'];//原因
    return $sailState?($stockState?"":"商品无货:{$msg}"):"商品不可销售:{$msg}";
}




/**
 * 全境供应链云-创建订单
 * @param array $goodsList 商品数组,包含goodsQty(商品数,string,必填)和skuId(SKUID,string,必填)
 * @param string $shipName 收货联系人姓名
 * @param string $shipAddress 收货地址
 * @param string $shipMobile 收货手机
 * @param string $shipAreaCode 收货地区编码
 * @param string $outOrderSn 外部订单号(分销商订单号)
 * @param string $buyerMemo  订单备注
 * @return array  返回全境供应链云端订单号
 */
function createOrderToApi(array $goodsList=[],string $shipName='',string $shipAddress='',string $shipMobile='',string $shipAreaCode='',string $outOrderSn='',string $buyerMemo=''):array{
    $sceApiService=new \fast\SceApiService();
    $resp=$sceApiService->submitOrder($goodsList,$shipName,$shipAddress,$shipMobile,$shipAreaCode,$outOrderSn,$buyerMemo);
    if(is_array($resp) && isset($resp['code'])) return $resp;
    return $resp['orderList']&&$resp['orderList'][0]?['orderSn'=>$resp['orderList'][0]['orderSn']]:[];
}




/**
 * 全境供应链云-修改订单收货地址
 * @param string $shipMobile 收货手机
 * @param string $orderSn 订单编号
 * @param string $shipName 收货联系人姓名
 * @param string $shipAddress 收货地址
 * @param string $shipAreaCode 收货地区编码
 * @return array
 */
function updateOrderReceiveAddress(string $shipMobile='',string $orderSn='',string $shipName='',string $shipAddress='',string $shipAreaCode=''):array{
    $sceApiService=new \fast\SceApiService();
    $resp=$sceApiService->updateOrderReceiveAddress($shipMobile,$orderSn,$shipName,$shipAddress,$shipAreaCode);
    if(is_array($resp) && isset($resp['code'])) return $resp;
    return ['bool'=>$resp?true:false];
}



/**
 * 全境供应链云-确认收货
 * @param string $orderSn 云端订单编号
 * @param string $operator 操作人
 * @return boolean
 */
function confirmReceive(string $orderSn='',string $operator=''):array{
    $sceApiService=new \fast\SceApiService();
    $resp=$sceApiService->confirmReceive($orderSn,$operator);
    if(is_array($resp) && isset($resp['code'])) return $resp;
    return ['bool'=>$resp?true:false];
}



/**
 * 全境供应链云-售后申请
 * @param string $reason 退费原因
 * @param string $orderSn 订单编号
 * @param string $refundReasonId 退款原因ID, 请参考文档中心-订单售后申请原因说明文档
 * @param array $goodsList 退款商品数组,包含goodsQuantity(商品数,integer,是否必填:true),goodsSpecId(规格Id,string,是否必填:true),refundAmount(退款金额,售后类型为"部分退款"时必填,且最多支持2位小数,number,是否必填:true)
 * @param int $returnType 售后类型，1：退款，2：退货退款，3：换货，4：仅退款，5：部分退款
 * @param string $memo 备注信息
 * @return array
 */
function applyRefundToApi(string $reason='',string $orderSn='',string $refundReasonId='',array $goodsList=[],int $returnType=1,string $memo=''):array{
    $sceApiService=new \fast\SceApiService();
    $resp=$sceApiService->applyRefund($reason,$orderSn,$refundReasonId,$goodsList,$returnType,$memo);
    if(is_array($resp) && isset($resp['code'])) return $resp;
    return $resp;
}



/**
 * 构建退款状态信息
 * @param \app\api\model\wanlshop\Refund $refund
 * @param array $resp 接口返回的data数组
 * @param bool $updateCloudReturnSn 是否设置云端订单退款售后单号
 * @return \app\api\model\wanlshop\Refund
 */
function buildRefundState(\app\api\model\wanlshop\Refund $refund,array $resp,bool $updateCloudReturnSn=false):\app\api\model\wanlshop\Refund{
    //$resp['returnStatus']状态码如下
    $stateDesc = [
        1 => '待卖家审核',
        2 => '卖家拒绝退款',
        3 => '退款成功',
        4 => '卖家拒绝退货退款',
        5 => '待买家退货',
        6 => '买家已退货，待卖家收货',
        7 => '买家已退货，卖家拒绝收货',
        8 => '卖家已收货,待确认退款',
        9 => '退货退款成功',
        //10=>'卖家拒绝换货',
        //11=>'买家已退货，待卖家换货',
        //12=>'卖家已换货，待买家收货',
        //13=>'换货成功',
        14 => '已关闭',
        15 => '卖家同意退款',
        16 => '卖家同意退款',
        17 => '卖家拒绝退款',
        18 => '退款成功'
    ];

    $refund->state_desc = $stateDesc[$resp['returnStatus']];
    if($updateCloudReturnSn) $refund->cloud_returnSn=$resp['returnSn'];//订单退款售后单号
    if ($resp['returnType'] == 1) {//退款

        if (in_array($resp['returnStatus'], [1]))$refund->state = 0;//待卖家审核
        elseif (in_array($resp['returnStatus'], [2, 17]))$refund->state = 2;//卖家拒绝退款
        elseif (in_array($resp['returnStatus'], [15, 16]))$refund->state = 1;//卖家同意退款
        elseif (in_array($resp['returnStatus'], [3, 18]))$refund->state = 4;//退款成功
        elseif (in_array($resp['returnStatus'], [14]))$refund->state = 5;//已关闭

    } elseif ($resp['returnType'] == 2) {//退货退款

        if (in_array($resp['returnStatus'], [1]))$refund->state = 0;//待卖家审核
        elseif (in_array($resp['returnStatus'], [2, 17, 4]))$refund->state = 2;//卖家拒绝退货退款
        elseif (in_array($resp['returnStatus'], [5, 15, 16]))$refund->state = 1;//卖家同意退款
        elseif (in_array($resp['returnStatus'], [6, 7, 8]))$refund->state = 6;//买家已退货,已提交物流
        elseif (in_array($resp['returnStatus'], [7]))$refund->state = 3;//买家已退货，卖家拒绝收货,申请平台介入
        elseif (in_array($resp['returnStatus'], [3, 9, 18]))$refund->state = 4;//退款成功
        elseif (in_array($resp['returnStatus'], [14]))$refund->state = 5;//已关闭

    }
    return $refund;
}

/**
 * 全境供应链云-售后申请，只能提交不能修改
 * @param \app\api\model\wanlshop\Refund $refund 退款实例
 * @param \app\api\model\wanlshop\Order $order  订单实例
 * @param \app\api\model\wanlshop\OrderGoods $goods 订单商品实例
 * @return array
 */
function applyRefund(\app\api\model\wanlshop\Refund $refund,$order,$goods):array{
        if(!$refund['price']){
            //如果退款金额为0，则置为已关闭
            //构建退款状态
            $resp=['returnStatus'=>14,'returnType'=>intval($refund['type']) + 1];
            $refund = buildRefundState($refund,$resp,false);
            //$goods的退款状态:0=未退款,1=退款中,2=待退货,3=退款完成,4=退款关闭,5=退款被拒
            $goods['refund_status']=4;
            Db::startTrans();
            try {
                $goods->allowField(true)->save();
                $refund->allowField(true)->save();
                Db::commit();
                return [];
            }catch (\Exception $e){
                Db::rollback();
                return ['code'=>0,'msg'=>'退款单状态更新失败:'.$e->getMessage()];
            }
        }

        //$resp['returnType']:售后类型，1：退款，2：退货退款，3：换货，4：仅退款，5：部分退款,目前我们的商城支持1和2
        //$refund->reason:退货理由:0=不喜欢,1=空包裹,2=一直未送达,3=颜色/尺码不符,4=质量问题,5=少件漏发,6=假冒品牌
        $refund_reasonid_map = [
            0 => ['id' => 7, 'reason' => '不喜欢/不想要'],
            1 => ['id' => 24, 'reason' => '其他'],
            2 => ['id' => 15, 'reason' => '发货太慢'],
            3 => ['id' => 20, 'reason' => '货品不对'],
            4 => ['id' => 10, 'reason' => '质量问题'],
            5 => ['id' => 21, 'reason' => '少件/漏发'],
            6 => ['id' => 22, 'reason' => '假冒产品'],
        ];

        $refundReason = $refund_reasonid_map[$refund['reason']];

        $skuId = model('app\api\model\wanlshop\GoodsSku')
            ->where('goods_id', $goods['goods_id'])
            ->where('id', $goods['goods_sku_id'])->value('skuId');

        $resp = applyRefundToApi(
            $refundReason['reason'],
            $order['cloud_order_no'],
            $refundReason['id'], [[
            'goodsQuantity' => (int)$goods['number'],
            'goodsSpecId' => $skuId,
            'refundAmount' => floatval($refund['price']),
        ]], intval($refund['type']) + 1,$refund['refund_content']);
        if(!$resp) return ['code'=>0,'msg'=>'售后申请接口失败'];
        if(isset($resp['code'])) return $resp;

        //$refund['state']退款状态:0=申请退款,1=卖家同意,2=卖家拒绝,3=申请平台介入,4=成功退款,5=退款已关闭,6=已提交物流,7=第三方退款中,8=退款失败
        //构建退款状态
        $refund = buildRefundState($refund, $resp, true);
        //$goods['refund_status']退款状态:0=未退款,1=退款中,2=待退货,3=退款完成,4=退款关闭,5=退款被拒
        //$refund_goods_state_map: key=$refund['state'],value=$goods['refund_status']
        $refund_goods_state_map=[0=>1, 1=>2, 2=>5, 3=>1, 4=>3, 5=>4];
        //$refund['type']:0=我要退款(无需退货),1=退货退款;
        $goods['refund_status'] =$refund['state']==1?($refund['type']?2:3):$refund_goods_state_map[$refund['state']];

        Db::startTrans();
        try {
            $goods->allowField(true)->save();
            $refund->allowField(true)->save();
            Db::commit();
            return [];
        }catch (\Exception $e){
            Db::rollback();
            return ['code'=>0,'msg'=>'退款单状态更新失败:'.$e->getMessage()];
        }


}


/**
 * 全境供应链云-退货/换货邮寄卖家
 * @param \app\api\model\wanlshop\Refund $refund 退款实例
 * @param string $deliverySn 物流单号
 * @param string $deliveryCorpName 物流公司名称
 * @param array
 */
function sendReturnGoods(\app\api\model\wanlshop\Refund $refund,string $deliverySn='',string $deliveryCorpName='',string $returnSn=''):array{
    $sceApiService=new \fast\SceApiService();
    $resp=$sceApiService->sendReturnGoods($deliverySn,$deliveryCorpName,$returnSn);
    if(is_array($resp) && isset($resp['code'])) return $resp;
    if($resp) {
        //构建退款状态
        $refund = buildRefundState($refund, $resp, false);
        $refund->save();
    }
    return [];
}





/**
 * 全境供应链云-取消售后申请
 * @param \app\api\model\wanlshop\Refund $refund 退款实例
 * @return array
 */
function cancelRefund(\app\api\model\wanlshop\Refund $refund):array{
    $sceApiService=new \fast\SceApiService();
    $resp=$sceApiService->cancelRefund($refund['cloud_returnSn']);
    if(!$resp) return ['code'=>0,'取消售后申请接口出错'];
    if(is_array($resp) && isset($resp['code'])) return $resp;

    //构建退款状态
    $refund = buildRefundState($refund, $resp, false);
    $affect=$refund->allowField(true)->save();
    return $affect?[]:['code'=>0,'退款状态更新失败'];
}



/**
 * 全境供应链云-查询售后单详细信息
 * @param \app\api\model\wanlshop\Refund $refund 退款实例
 * @return array
 */
function refoundDetail(\app\api\model\wanlshop\Refund $refund):array{
    $sceApiService=new \fast\SceApiService();
    $resp=$sceApiService->detail($refund->cloud_returnSn);
    if(is_array($resp) && isset($resp['code'])) return $resp;
    if(!$resp) return ['refund'=>$refund];
    //构建退款状态
    $refund=buildRefundState($refund,$resp,false);
    $refund->allowField(true)->save();
    return ['refund'=>$refund];
}


/**
 * 全境供应链云-查询商品运费
 * @param array $spuInfoList 订单商品及数量,包含quantity(商品数量,integer,是否必填:true),spuId(商品spuId,integer,是否必填:true)
 * @param string $cityId 收货城市ID（二级区域编码)
 * @return array
 */
function calculateFreight(array $spuInfoList = [], string $cityId = ''):array{
    $sceApiService=new \fast\SceApiService();
    $resp=$sceApiService->calculate($spuInfoList,$cityId);
    if(is_array($resp) && isset($resp['code'])) return $resp;
    return ['freight_price'=>$resp];
}


/**
 * 全境供应链云-查询订单详情
 * @param \app\api\model\wanlshop\Order $order 订单实例
 * @param int $statusCode 全境云端订单状态码
 * @return array
 */
function getOrderDetail(\app\api\model\wanlshop\Order $order,int $statusCode=0):array{
    //分销商订单状态：订单状态:1=待支付,2=待发货,3=待收货,4=待评论,5=发货前或发货后关闭,6=已完成,7=已取消
    //供应链订单状态如下(key是供应链订单状态码,state是本地订单状态码):
    $stateDesc=[
        10=>['state'=>1,'text'=>'已提交待付款'],
        20=>['state'=>2,'text'=>'已付款待发货'],
        30=>['state'=>3,'text'=>'已发货待收货'],
        40=>['state'=>4,'text'=>'确认收货交易成功'],
        50=>['state'=>7,'text'=>'用户超时未支付订单自动取消'],
        70=>['state'=>5,'text'=>'订单发货前售后关闭'],
        80=>['state'=>5,'text'=>'订单发货后售后关闭'],
    ];

    if($statusCode) {
        //有全境云端订单状态码的情况下，只更新订单的状态
        $order->state=$stateDesc[$statusCode]['state'];
    }else {
        $sceApiService = new \fast\SceApiService();
        $resp = $sceApiService->getOrderDetail($order['cloud_order_no']);
        if (is_array($resp) && isset($resp['code'])) return $resp;
        if (!$resp) return ['order' => $order];
        //$resp['deliverList'] 是一个数组,这里取最开始的一个
        $deliverList = $resp['deliverList'] ? $resp['deliverList'][count($resp['deliverList']) - 1] : [];
        $expressName = $deliverList ? $deliverList['expressName'] : '';
        $deliveryCorpSn = $deliverList ? $deliverList['deliveryCorpSn'] : '';
        $deliverySn = $deliverList ? $deliverList['deliverySn'] : '';
        $sendTime = $deliverList ? $deliverList['sendTime'] : '';
        $order->express_name = $expressName;
        $order->express_code = $deliveryCorpSn;
        $order->express_no = $deliverySn;
        $order->delivertime = strtotime($sendTime);
        $order->state = $stateDesc[$resp['orderStatus']]['state'];
    }
    $order->allowField(true)->save();
    return ['order'=>$order];
}




/**
 * 全境供应链云-查询物流信息
 * @param \app\api\model\wanlshop\Order $order 订单实例
 * @return array
 */
function getOrderExpressListByOs(\app\api\model\wanlshop\Order $order):array
{
    if(!$order['express_no']) return [];
    $sceApiService=new \fast\SceApiService();
    $resp=$sceApiService->getOrderExpressListByOs($order['express_no'],$order['cloud_order_no']);
    if(is_array($resp) && isset($resp['code'])) return $resp;
    if(!$resp) return [];
    if(!$resp[0])return [];
    return $resp[0];
}





/**
 * 小程序发货-发货信息录入到微信商户平台
 * @param array $orderData 订单数据(按照小程序发货格式要求)
 * @return array errcode number	错误码，errmsg string 错误原因
 */
function upload_shipping_info(array $orderData):array{
    //发货信息录入接口，文档地址:https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order-shipping/order-shipping.html#%E4%B8%80%E3%80%81%E5%8F%91%E8%B4%A7%E4%BF%A1%E6%81%AF%E5%BD%95%E5%85%A5%E6%8E%A5%E5%8F%A3
    $config=get_addon_config('wanlshop');
    $http = Http::get("https://api.weixin.qq.com/cgi-bin/token", [
        'grant_type' => 'client_credential',
        'appid'      => $config['mp_weixin']['appid'],
        'secret'     => $config['mp_weixin']['appsecret']
    ]);
    $json = json_decode($http, true);
    if(!empty($json['access_token'])){
        $url="https://api.weixin.qq.com/wxa/sec/order/upload_shipping_info?access_token={$json['access_token']}";
        $resp= json_decode(Http::post($url, json_encode($orderData, JSON_UNESCAPED_UNICODE)), true);
        return ['code' => $resp['errcode'] ,'msg' => $resp['errmsg']];
    }else{
        return ['code' => $json['errcode'] ,'msg' => '请求失败：可能后台小程序的appid、appsecret配置错误，具体：'. $json['errmsg']];
    }
}


/**
 * 小程序发货-获取微信商户平台物流公司列表
 * @return array
 */
function get_delivery_list():array{
    $config=get_addon_config('wanlshop');
    $http = Http::get("https://api.weixin.qq.com/cgi-bin/token", [
        'grant_type' => 'client_credential',
        'appid'      => $config['mp_weixin']['appid'],
        'secret'     => $config['mp_weixin']['appsecret']
    ]);
    $json = json_decode($http, true);
    if(!empty($json['access_token'])){
        $url="https://api.weixin.qq.com/cgi-bin/express/delivery/open_msg/get_delivery_list?access_token={$json['access_token']}";
        $resp= json_decode(Http::post($url,'{}'), true);
        //$resp['delivery_list']是一个二维数组,如 $resp['delivery_list']=[['delivery_id'=> 007EX,'delivery_name'=>'俄顺达']]
        return ['code' => $resp['errcode'] ,'msg' => $resp['delivery_list']];
    }else{
        return ['code' => $json['errcode'] ,'msg' => '请求失败：可能后台小程序的appid、appsecret配置错误，具体：'. $json['errmsg']];
    }
}





/**
 * 根据物流公司代码获取物流公司名称
 * @param string $deliveryCorpSn 全境物流公司代码
 * @return array
 */
function getExpressNameByDeliveryCorpSn(string $deliveryCorpSn):array{
    //key:全境快递公司代码,qj_text:全境快递公司名称,wx_code:微信商户平台快递公司代码,wx_text:微信商户平台快递公司名称
    $expressNameList=[
        'shunfeng'=>['qj_name'=>'顺丰速运','wx_code'=>'SF','wx_name'=>'顺丰速运'],
        'yuantong'=>['qj_name'=>'圆通速递','wx_code'=>'YTO','wx_name'=>'圆通速递'],
        'zhongtong'=>['qj_name'=>'中通快递','wx_code'=>'ZTO','wx_name'=>'中通快递'],
        'shentong'=>['qj_name'=>'申通快递','wx_code'=>'STO','wx_name'=>'申通快递'],
        'yunda'=>['qj_name'=>'韵达快递','wx_code'=>'YD','wx_name'=>'韵达速递'],
        'huitongkuaidi'=>['qj_name'=>'百世快递','wx_code'=>'HTKY','wx_name'=>'百世快递'],
        'debangwuliu'=>['qj_name'=>'德邦','wx_code'=>'DBLKY','wx_name'=>'德邦快运/德邦物流'],
        'quanfengkuaidi'=>['qj_name'=>'全峰快递','wx_code'=>'','wx_name'=>''],//微信中没有该快递
        'tiantian'=>['qj_name'=>'天天快递','wx_code'=>'','wx_name'=>''],//微信中没有该快递
        'suer'=>['qj_name'=>'速尔快递','wx_code'=>'SURE','wx_name'=>'速尔快递'],
        'youshuwuliu'=>['qj_name'=>'优速','wx_code'=>'UC','wx_name'=>'优速快递'],
        'tiandihuayu'=>['qj_name'=>'天地华宇','wx_code'=>'HOAU','wx_name'=>'天地华宇'],
        'youzhengguonei'=>['qj_name'=>'邮政快递包裹','wx_code'=>'YZPY','wx_name'=>'邮政快递包裹'],
        'exfresh'=>['qj_name'=>'安鲜达','wx_code'=>'AXD','wx_name'=>'安鲜达'],
        'rrs'=>['qj_name'=>'日日顺物流','wx_code'=>'RRS','wx_name'=>'日日顺物流'],
        'youzhengguoji'=>['qj_name'=>'国际包裹','wx_code'=>'','wx_name'=>''],//微信中没有该快递
        'jd'=>['qj_name'=>'京东物流','wx_code'=>'JD','wx_name'=>'京东快递'],
        'suning'=>['qj_name'=>'苏宁物流','wx_code'=>'SNWL','wx_name'=>'苏宁物流'],
        'huolalawuliu'=>['qj_name'=>'货拉拉物流','wx_code'=>'','wx_name'=>''],//微信中没有该快递
        'wanxiangwuliu'=>['qj_name'=>'万象物流','wx_code'=>'','wx_name'=>''],//微信中没有该快递
        'annengwuliu'=>['qj_name'=>'安能快运','wx_code'=>'ANEKY','wx_name'=>'安能物流'],
        'xinfengwuliu'=>['qj_name'=>'信丰物流','wx_code'=>'XFEX','wx_name'=>'信丰物流'],
        'zhaijisong'=>['qj_name'=>'宅急送','wx_code'=>'ZJS','wx_name'=>'宅急送'],
        'guotongkuaidi'=>['qj_name'=>'国通快递','wx_code'=>'','wx_name'=>''],//微信中没有该快递
        'ems'=>['qj_name'=>'EMS','wx_code'=>'EMS','wx_name'=>'EMS'],
        'quanyikuaidi'=>['qj_name'=>'全一快递','wx_code'=>'UAPEX','wx_name'=>'全一快递'],
        'ztky'=>['qj_name'=>'中铁快运','wx_code'=>'ZTWL','wx_name'=>'中铁物流'],
        'pjbest'=>['qj_name'=>'品骏快递','wx_code'=>'PJ','wx_name'=>'品骏快递'],
        'huangmajia'=>['qj_name'=>'黄马甲','wx_code'=>'','wx_name'=>''],//微信中没有该快递
        'nanjingshengbang'=>['qj_name'=>'晟邦物流','wx_code'=>'NJSBWL','wx_name'=>'南京晟邦物流'],
        'annto'=>['qj_name'=>'安得物流','wx_code'=>'ANNTO','wx_name'=>'安得物流'],
        'jiayunmeiwuliu'=>['qj_name'=>'加运美','wx_code'=>'JYM','wx_name'=>'加运美'],
        'zhuanyunsifang'=>['qj_name'=>'转运四方','wx_code'=>'A4PX','wx_name'=>'转运四方'],
        'yimidida'=>['qj_name'=>'壹米滴答','wx_code'=>'YMDD','wx_name'=>'壹米滴答'],
        'zhimakaimen'=>['qj_name'=>'芝麻开门','wx_code'=>'','wx_name'=>''],//微信中没有该快递
        'kuayue'=>['qj_name'=>'跨越速运','wx_code'=>'KYSY','wx_name'=>'跨越速运'],
        'yundakuaiyun'=>['qj_name'=>'韵达快运','wx_code'=>'YDKY','wx_name'=>'韵达快运'],
        'sxjdfreight'=>['qj_name'=>'顺心捷达','wx_code'=>'SX','wx_name'=>'顺心捷达'],
        'lntjs'=>['qj_name'=>'特急送','wx_code'=>'TJS','wx_name'=>'特急送'],
        'baishiwuliu'=>['qj_name'=>'百世快运','wx_code'=>'BTWL','wx_name'=>'百世快运'],
        'jiuyescm'=>['qj_name'=>'九曳供应链','wx_code'=>'JIUYE','wx_name'=>'九曳供应链'],
        'danniao'=>['qj_name'=>'丹鸟','wx_code'=>'DNWL','wx_name'=>'丹鸟物流'],
        'subida'=>['qj_name'=>'速必达','wx_code'=>'SUBIDA','wx_name'=>'速必达物流'],
        'jinguangsudikuaijian'=>['qj_name'=>'京广速递','wx_code'=>'JGSD','wx_name'=>'京广速递'],
        'lianhaowuliu'=>['qj_name'=>'联昊通','wx_code'=>'LHT','wx_name'=>'联昊通速递'],
        'jtexpress'=>['qj_name'=>'极兔速递','wx_code'=>'JTSD','wx_name'=>'极兔速递'],
        'ftky365'=>['qj_name'=>'丰通快运','wx_code'=>'FT','wx_name'=>'丰通快运'],
        'sanzhi56'=>['qj_name'=>'三志物流','wx_code'=>'','wx_name'=>''],//微信中没有该快递
        'zhongtongkuaiyun'=>['qj_name'=>'中通快运','wx_code'=>'ZTOKY','wx_name'=>'中通快运'],
        'youzhengdsbk'=>['qj_name'=>'邮政电商标快','wx_code'=>'','wx_name'=>''],//微信中没有该快递
        'youzhengbk'=>['qj_name'=>'邮政标准快递','wx_code'=>'','wx_name'=>''],//微信中没有该快递
        'shunfengkuaiyun'=>['qj_name'=>'顺丰快运','wx_code'=>'SF','wx_name'=>'顺丰速运'],
        'savor'=>['qj_name'=>'海信物流','wx_code'=>'HISENSE','wx_name'=>'海信物流'],
        'pingandatengfei'=>['qj_name'=>'平安达腾飞','wx_code'=>'PADTF','wx_name'=>'平安达腾飞快递'],
        'cainiaozhisong'=>['qj_name'=>'菜鸟速递','wx_code'=>'','wx_name'=>''],//微信中没有该快递
    ];
    return $expressNameList[$deliveryCorpSn];
}


/**
 * 退款/退款退货
 * @param $refund 退款单实例
 * @return array
 */
function refund($refund):array{
    /**
     * 更新订单商品状态（方法内使用）1.0.5升级
     *
     * @ApiSummary  (WanlShop 更新订单商品状态)
     * @ApiMethod   (POST)
     *
     * @param string $status 状态
     * @param string $goods_id 商品ID
     */
    function setOrderGoodsState($status = 0, $goods_id = 0, $order_type = 'goods'){
        if($order_type === 'groups'){
            $orderGoodsModel = model('app\admin\model\wanlshop\GroupsOrderGoods');
        }else{
            $orderGoodsModel = model('app\admin\model\wanlshop\OrderGoods');
        }
        return $orderGoodsModel->save(['refund_status' => $status],['id' => $goods_id]);
    }


    /**
     * 修改订单状态（方法内使用） 1.0.5升级
     *
     * @ApiSummary  (WanlShop 修改订单状态)
     * @ApiMethod   (POST)
     *
     * @param string $id 订单ID
     */
    function setRefundState($order_id = 0, $order_type = 'goods'){
        if($order_type === 'groups'){
            $orderModel = model('app\admin\model\wanlshop\GroupsOrder');
            $orderGoodsModel = model('app\admin\model\wanlshop\GroupsOrderGoods');
        }else{
            $orderModel = model('app\admin\model\wanlshop\Order');
            $orderGoodsModel = model('app\admin\model\wanlshop\OrderGoods');
        }
        $list = $orderGoodsModel
            ->where(['order_id' => $order_id])
            ->select();
        $refundStatusCount = 0;
        foreach($list as $row){
            // 退款状态:0=未退款,1=退款中,2=待退货,3=退款完成,4=退款关闭,5=退款被拒
            if($row['refund_status'] == 3) $refundStatusCount += 1;
        }
        // 订单状态:1=待支付,2=待发货,3=待收货,4=待评论,5=售后订单(已弃用),6=已完成,7=已取消 1.0.5升级
        // 如果订单下所有商品全部退款完毕则关闭订单
        if(count($list) == $refundStatusCount){
            $orderModel->save(['state'  => 7],['id' => $order_id]);
            return true;
        }
        return false;
    }

    /**
     * 退款日志（方法内使用）
     *
     * @ApiSummary  (WanlShop 退款日志)
     *
     * @param string $user_id 用户ID
     * @param string $refund_id 退款ID
     * @param string $content 日志内容
     * @param string $type 退款状态:0=买家,1=卖家,2=官方,3=系统
     */
    function refundLog($user_id = 0, $refund_id = 0, $content = '', $type = 2){
        return model('app\api\model\wanlshop\RefundLog')->allowField(true)->save([
            'user_id' => $user_id,
            'refund_id' => $refund_id,
            'type' => $type,
            'content' => $content
        ]);
    }

    $pay=$refund->pay;
    // 判断金额
    if(number_format($refund['price'], 2) > number_format($pay->price, 2)){
        return ['code'=>0,'msg'=>'非法退款金额，金额超过订单金额！！'];
    }

    // 退款日志
    $refundLog = '平台判定卖家需配合买家完成退货';
    // 退款类型
    $refundType = 2;

    Db::startTrans();
    try {
        // 判断退款类型
        if($refund['type'] == 0){
            // 退款完成
            $state = 4;
            $orderGoodsState = 3;
            // 如果使用了余额抵扣，则把余额退回并写入日志
            if($pay['used_balance']>0) {
                controller('addons\wanlshop\library\WanlPay\WanlPay')->money(+$pay['used_balance'], $refund['user_id'], '客服判定同意退款', 'refund', $refund['pay']['order_no']);
            }
            // 1.1.5升级 第三方退款 1.1.9升级
            $config = get_addon_config('wanlshop');
            // 检查是否原路返还
            if($config['config']['refund_switch'] == 'Y')
            {
                $refundType = 3;
                $wanlpay = controller('addons\wanlshop\library\WanlPay\WanlPay')->refund($refund['id'], $refund['price'], $refund['order_pay_id'],$pay['used_balance']);
                // code=0同步方法：refund判断fund_change = Y，代表退款成功，支付宝文档《如何判断退款是否成功》，https://opendocs.alipay.com/support/01rawa
                if($wanlpay['code'] == 0)
                {
                    // 退款中
                    $state = 4;
                    // 退款日志
                    $refundLog = '平台判定卖家需配合买家完成退货，已提交'.$wanlpay['data']['type_text'].'已将退款￥'.$wanlpay['data']['money'].'元原路返还买家'.$wanlpay['data']['type_text'].'账户';
                    // 扣除本地用户余额
                    controller('addons\wanlshop\library\WanlPay\WanlPay')->money(-$wanlpay['data']['money'], $wanlpay['data']['user_id'], '退款订单（订单号：'.$refund->order->order_no.'）已原路返回余额至你的'.$wanlpay['data']['type_text'], 'sys');
                    // 如果退款成功,修改退款状态为第三方退款中，等待回调,否则退款到余额
                }else if($wanlpay['code'] == 200){
                    // 退款中
                    $state = 7;
                    // 退款日志
                    $refundLog = '平台判定卖家需配合买家完成退货，已提交'.$wanlpay['data']['type_text'].'处理，预计24小时内将退款'.$wanlpay['data']['actual_money'].'元原路返还给买家'.$wanlpay['data']['type_text'].'账户';
                    // 扣除本地供应商余额
                    controller('addons\wanlshop\library\WanlPay\WanlPay')->money(-$wanlpay['data']['money'], $wanlpay['data']['user_id'], '退款订单（订单号：'.$refund->order->order_no.'）已原路返回余额至你的'.$wanlpay['data']['type_text'], 'sys');
                    // 1.1.6升级
                }else if($wanlpay['code'] == 1){
                    //支付方式为余额支付，余额实时退款
                    $refundLog = '平台判定卖家需配合买家完成退货，'.$refund['price'].'元退款到买家账号余额';
                }else{
                    $refundLog = '平台判定卖家需配合买家完成退货，第三方支付退款失败已转入余额，请手动提现';
                }
            }
            //后续版本推送订购单
            // ...
        }else if($refund['type'] == 1){
            // 先同意退款，还需要买家继续退货
            $state = 1;
            $orderGoodsState = 2;
        }else{
            return ['code'=>0,'msg'=>'非法退款类型'];
        }
        // 只有本地余额退款状态4,和先同意退款,需要商家继续退款状态1执行,状态7原路返回在回调更新状态
        // 退款状态:0=申请退款,1=卖家同意,2=卖家拒绝,3=申请平台介入,4=成功退款,5=退款已关闭,6=已提交物流,7=第三方退款中,8=退款失败
        if($state == 1 || $state == 4){
            // 更新商品状态
            setOrderGoodsState($orderGoodsState, $refund['goods_ids'], $refund['order_type']);
            // 更新订单状态
            setRefundState($refund['order_id'], $refund['order_type']);
        }
        // 写入日志
        refundLog($refund['user_id'], $refund['id'], $refundLog, $refundType);
        // 更新退款
        $state_desc=$state==1?'卖家同意':($state==4?'成功退款':($state==7?'退款中':'未知'));
        $result = $refund->allowField(true)->save([
            'state' => $state,
            'state_desc'=>$state_desc,
            'completetime' => time()
        ]);
        Db::commit();
    } catch (PDOException $e) {
        Db::rollback();
        return ['code'=>0,'msg'=>$e->getMessage()];
    } catch (Exception $e) {
        Db::rollback();
        return ['code'=>0,'msg'=>$e->getMessage()];
    }
    return $result? ['code'=>1,'msg'=>'退款成功']:['code'=>0,'msg'=>'退款异常'];
}



